Pytorch 기본 문법 이해

텐서 인덱싱, 조건 연산 및 저장

한지희

2023-10-01

Tensor Indexing

  • indexing: 텐서의 특정 데이터 가져오기 tensor_indexing

Tensor Indexing

data1 = torch.FloatTensor([[0, 1, 2, 3, 4], 
[5, 6, 7, 8, 9], 
[10, 11, 12, 13, 14]])
print(data1, data1.shape)
print(data1[1,2])
print(data1[:, 1])
print(data1[:,-1])
print(data1[:, :]) #전체
tensor([[ 0.,  1.,  2.,  3.,  4.],
        [ 5.,  6.,  7.,  8.,  9.],
        [10., 11., 12., 13., 14.]]) torch.Size([3, 5])
tensor(7.)
tensor([ 1.,  6., 11.])
tensor([ 4.,  9., 14.])
tensor([[ 0.,  1.,  2.,  3.,  4.],
        [ 5.,  6.,  7.,  8.,  9.],
        [10., 11., 12., 13., 14.]])

Boolean Indexing

data1 = torch.FloatTensor([[0, 1, 2, 3, 4], 
[5, 6, 7, 8, 9], 
[10, 11, 12, 13, 14]])
data2 = data1 > 7
print(data2) #T/F 출력
print(data1[data2]) #T인 값만 추출
tensor([[False, False, False, False, False],
        [False, False, False,  True,  True],
        [ True,  True,  True,  True,  True]])
tensor([ 8.,  9., 10., 11., 12., 13., 14.])
print(data1[(data1 < 3)| (data1 > 11)])
tensor([ 0.,  1.,  2., 12., 13., 14.])

Fancy Indexing

  • Fancy Indexing: 배열로 배열을 인덱싱
  • 특정 행 배열 추출
data1 = torch.randn(4,3)
print(data1)
print(data1[[1,2]])
print(data1[[2,1]])
tensor([[ 1.7193,  1.9017, -0.8862],
        [ 0.5545, -0.5778, -1.1100],
        [-0.6666,  0.8761, -0.1472],
        [ 1.3535,  0.3136, -0.4402]])
tensor([[ 0.5545, -0.5778, -1.1100],
        [-0.6666,  0.8761, -0.1472]])
tensor([[-0.6666,  0.8761, -0.1472],
        [ 0.5545, -0.5778, -1.1100]])
  • 특정 행과 열 추출
print(data1[[1,2]][:, [0,2]])
tensor([[ 0.5545, -1.1100],
        [-0.6666, -0.1472]])

Shallow vs. Deep copy

copy

Shallow copy

data1 = torch.FloatTensor([[1, 2, 3],[4, 5, 6]])
print(data1)
data2 = data1[:2, :2]
data2[1, 1] = 4
print(data2)
print(data1)
tensor([[1., 2., 3.],
        [4., 5., 6.]])
tensor([[1., 2.],
        [4., 4.]])
tensor([[1., 2., 3.],
        [4., 4., 6.]])

Deep copy: .clone().detach()

  • .clone(): 새로운 메모리 할당 (.requires_grad=True, NO in-place operation error)
  • .detach(): 계산 그래프에서 배제 (.requires_grad=False, YES in-place operation error)
    • in-place operation error: 불변성을 유지해야 하는 데이터 구조(gradient 계산)에서의 변경으로 인한 오류
    • requires_grad: 텐서가 gradient 계산해야 하는지 여부(True: 계산 활성화)
data1 = torch.ones(5, requires_grad=True)
print(data1)

data2 = data1.clone()
data2[1] = 2
print(data1, data2.requires_grad)

data3 = data1.detach()
data3[1] = 3
print(data1, data3.requires_grad)
tensor([1., 1., 1., 1., 1.], requires_grad=True)
tensor([1., 1., 1., 1., 1.], requires_grad=True) True
tensor([1., 3., 1., 1., 1.], requires_grad=True) False

Deep copy: .clone().detach()

※ 참고: .clone().detach() vs. .detach().clone()

  • 역할은 동일하지만 .detach().clone()이 조금 더 빠르다! 1
data1 = torch.ones(5, requires_grad=True)
print(data1)

data2 = data1.clone().detach()
data2[1] = 2
print(data1, data2.requires_grad)

data3 = data1.detach().clone()
data3[1] = 3
print(data1, data3.requires_grad)
tensor([1., 1., 1., 1., 1.], requires_grad=True)
tensor([1., 1., 1., 1., 1.], requires_grad=True) False
tensor([1., 1., 1., 1., 1.], requires_grad=True) False

Deep copy: .clone().detach()

※ 참고: .clone().detach() vs. .detach().clone()

  • 역할은 동일하지만 .detach().clone()이 조금 더 빠르다! 1 detachclone graph

Tensor Condition Operation: where()

  • torch.where(condition, if true, if false)
  • 조건에 맞는 값 indexing
data1 = torch.FloatTensor([7, 2, 0, 4, 1])
index = torch.where(data1 < 3)
print(index)
print(data1[index])
(tensor([1, 2, 4]),)
tensor([2., 0., 1.])
  • 조건에 맞는 값 변환
data2 = torch.where(data1 < 3, -1, 1)
print(data2)
tensor([ 1, -1, -1,  1, -1])
  • 다차원 배열에도 적용 가능

Tensor Data Analysis

data1 = torch.FloatTensor([ [1, 2, 3], [4, 5, 6] ])
print (data1.min())
print (data1.max())
print (data1.sum())
print (data1.mean())
print (data1.var())
print (data1.std())
print (data1.argmin()) #인덱스
print (data1.argmax()) #인덱스
tensor(1.)
tensor(6.)
tensor(21.)
tensor(3.5000)
tensor(3.5000)
tensor(1.8708)
tensor(0)
tensor(5)

Save and Load Tensor

(1) 텐서가 하나일 때

  • torch.save(배열, ‘파일명.pt’): 텐서를 파일로 저장
  • torch.load(): 파일로 저장된 1차원 배열 읽어오기
data1 = torch.linspace(1, 5, 4)
print(data1)
torch.save(data1, 'mydata1.pt')

data2 = torch.load('mydata1.pt')
print(data2)
tensor([1.0000, 2.3333, 3.6667, 5.0000])
tensor([1.0000, 2.3333, 3.6667, 5.0000])

saved files

Save and Load Tensor

(2) 텐서가 여러개일 때

  • 각 배열을 딕셔너리 형태(key: 배열)로 지정 후 저장
  • key값을 활용해서 각 배열을 읽어올 수 있음
data1 = torch.linspace(1, 5, 4)
data2 = torch.linspace(1, 10, 4)
data3 = torch.linspace(1, 100, 4)
print (data1)
print (data2)
print (data3)

datas1 = {'data1': data1, 'data2': data2, 'data3': data3}
torch.save(datas1, 'mydata2.pt')

datas2 = torch.load('mydata2.pt')
print (datas2['data1'])
print (datas2['data2'])
print (datas2['data3'])
tensor([1.0000, 2.3333, 3.6667, 5.0000])
tensor([ 1.,  4.,  7., 10.])
tensor([  1.,  34.,  67., 100.])
tensor([1.0000, 2.3333, 3.6667, 5.0000])
tensor([ 1.,  4.,  7., 10.])
tensor([  1.,  34.,  67., 100.])